package com.xishu.service;

import com.xishu.bo.Stock;
import com.xishu.config.Constant;
import com.xishu.dao.jpa.ItemDao;
import com.xishu.entity.NameAndId;
import com.xishu.entity.foodpanda.Product;
import com.xishu.entity.order.OrderItem;
import com.xishu.entity.shop.*;
import com.xishu.exception.ResponseStatusException;
import com.xishu.foodpanda.FoodPandaConfigService;
import com.xishu.response.ResponseStatus;
import com.xishu.response.VerifyUtil;
import com.xishu.service.order.base.OrderService;
import com.xishu.util.BeanUtil;
import com.xishu.util.Tools;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.zookeeper.Op;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商品服务
 */
public class ItemService implements Tools {
    private static ItemService instance = new ItemService();
    private static Logger logger = LoggerFactory.getLogger(ItemService.class);
    private CommonService commonService = CommonService.getInstance();


    private ItemService() {
    }

    public static ItemService getInstance() {
        return instance;
    }

    /**
     * 查询菜品
     *
     * @param itemId
     * @return
     * @throws InterruptedException
     * @throws ClassNotFoundException
     * @throws ResponseStatusException
     * @throws IOException
     */
    public Item findItem(Long itemId) throws Exception {
        logger.info("will find item id {}", itemId);
        Item item = new Item();
        item.setEntity(true);
        item.setId(itemId);
        return CommonService.getInstance().findEntity(item, true);
    }

    /**
     * 查询菜品
     *
     * @param itemId
     * @return
     */
    public Optional<Item> findItemOption(Long itemId) {
        if (itemId == null) {
            logger.info("item id is null");
            return Optional.empty();
        }

        try {
            return Optional.of(findItem(itemId));
        } catch (Exception e) {
            return Optional.empty();
        }
    }

    /**
     * 查询商品
     *
     * @param itemId
     * @param itemList
     * @return
     */
    public Optional<Item> findItemOption(Long itemId, List<Item> itemList) {
        Optional<Item> itemOptional = getList(itemList).stream().filter(p -> equals(p.getId(), itemId)).findAny();
        if (itemOptional.isPresent()) {
            return itemOptional;
        }

        Optional<Item> itemOptionInDb = findItemOption(itemId);
        if (itemOptionInDb.isPresent()) {
            itemList.add(itemOptionInDb.get());
            return itemOptionInDb;
        }

        return Optional.empty();
    }

    /**
     * 查询所有的ID列表
     *
     * @param itemIdList
     * @return
     */
    public List<Item> findItemByItemList(Collection<Long> itemIdList) {
        if (isEmpty(itemIdList)) {
            logger.info("item id list is empty");
            return new ArrayList<Item>();
        }

        List<Item> itemList = itemIdList.stream().map(itemId -> {
            try {
                return findItem(itemId);
            } catch (Exception e) {
                logger.error("e", e);
                return null;
            }
        }).filter(p -> p != null).collect(Collectors.toList());

        //如果有菜品被删除了，需要打日志
        if (itemList.size() != itemIdList.size()) {
            logger.info("size is diff, after query size is {}, before size is {}", itemList.size(), itemIdList.size());
        }

        return itemList;
    }

    /**
     * 查询所有的建议的商品
     * 后续加缓存
     *
     * @param shopId
     * @return
     */
    public List<Item> findAllSuggestionItem(Long shopId, Boolean online) {
        Item item = new Item();
        item.setShopId(shopId);
        item.setSuggestionOnline(online);
        item.setSuggestion(true);
        item.setEntity(true);
        List<Item> itemList = commonService.searchAll(item);
        logger.info("online suggestion item size is {}", itemList.size());

        return filterSuggestionItem(itemList);
    }

    /**
     * 过滤推荐菜的显示
     *
     * @param itemList
     * @return
     */
    public List<Item> filterSuggestionItem(List<Item> itemList) {
        return itemList.stream().filter(item -> {
            try {
                return filterSuggestionItemShow(item);
            } catch (Exception e) {
                logger.error("e", e);
                return false;
            }
        }).collect(Collectors.toList());
    }

    /**
     * 过滤商品是否可以显示
     *
     * @param item
     * @return
     */
    public boolean filterSuggestionItemShow(Item item) throws Exception {
        //所有时间均是一个价格
        if (isEmpty(item.getSceneList())) {
            return false;
        }

        for (NameAndId sceneIdList : item.getSceneList()) {
            Long sceneId = sceneIdList.getId();
            Scene scene = SceneService.getInstance().findScene(sceneId);
            if (getBoolean(scene.getEnable()) && SceneService.getInstance().isMatchTime(scene)) {
                logger.info("find the scene id {}", scene.getId());
                return true;
            }
        }

        logger.info("can not find the match scene for item id {}", item.getId());
        return false;
    }

    /**
     * 过滤菜品的显示
     *
     * @param itemList
     * @return
     */
    public List<Item> filterItemListShow(List<Item> itemList) {
        //查询是否设置了场景价格，如果设置了场景价格，那么商品必须要在这个场景下开启
        return itemList.stream().filter(i -> {
            try {
                return filterItemShow(i);
            } catch (Exception e) {
                logger.error("e", e);
                return false;
            }
        }).collect(Collectors.toList());
    }

    /**
     * 过滤商品是否可以显示
     *
     * @param item
     * @return
     */
    public boolean filterItemShow(Item item) throws Exception {
        //所有时间均是一个价格
        if (isEmpty(item.getPriceConfigList())) {
            return true;
        }


        for (PriceConfig priceConfig : item.getPriceConfigList()) {
            Long sceneId = priceConfig.getSceneId();
            Scene scene = CommonService.getInstance().findEntity(sceneId, Scene.class);
            if (getBoolean(priceConfig.getEnable()) && getBoolean(scene.getEnable()) && SceneService.getInstance().isMatchTime(scene)) {
                logger.info("find the scene id {}", scene.getId());
                return true;
            }
        }

        logger.info("can not find the match scene for item id {}", item.getId());
        return false;
    }

    /**
     * 查询套餐，后续加缓存
     *
     * @param shopId
     * @return
     */
    public List<Item> findSetMenuItem(Long shopId, Boolean online) {
        Item item = new Item();
        item.setShopId(shopId);
        item.setOnline(online);
        item.setSetMenu(true);
        item.setEntity(true);
        List<Item> itemList = commonService.searchAll(item);

        //过滤当前可以显示的
        return filterItemListShow(itemList);
    }


    /**
     * 计算规格项的价格
     *
     * @param itemInDb
     * @param itemDetailList
     * @return
     */
    public Double calAdditionalPrice(Item itemInDb, List<ItemDetail> itemDetailList) throws ResponseStatusException {
        //没有配置，但是传过来了需要配置
        if (isEmpty(itemInDb.getItemDetailList()) && isNotEmpty(itemDetailList)) {
            VerifyUtil.throwError(ResponseStatus.CONFIG_WRONG);
        }

        //客人没有选择规格项，那么直接返回0
        if (isEmpty(itemDetailList)) {
            logger.info("not select item detail");
            return 0d;
        }

        //选了规格项，那么就要传ID
        for (ItemDetail itemDetail : itemDetailList) {
            VerifyUtil.verify(() -> itemDetail.getId() != null, ResponseStatus.CONFIG_WRONG);
        }

        double sum = 0d;
        List<NameAndPrice> nameAndPriceList = itemDetailList.stream().flatMap(p -> p.getNameAndPriceList().stream()).collect(Collectors.toList());
        for (NameAndPrice nameAndPrice : nameAndPriceList) {
            logger.info("nameAndPrice is {}", nameAndPrice);
            VerifyUtil.verify(() -> nameAndPrice.getId() != null, ResponseStatus.CONFIG_WRONG);
            NameAndPrice findTheNameAndPrice = filterNameAndPrice(nameAndPrice.getId(), itemInDb);
            sum = sum + getDouble(findTheNameAndPrice.getPrice());
        }

        return showDouble(sum);
    }

    /**
     * 过滤套餐里面的某一个菜
     * <p>
     * 先过滤菜里面的某一个标签，再过滤标签下面的某一个菜
     *
     * @param itemInDb
     * @param itemId
     * @return
     */
    public Item filterItemInSetMenu(Item itemInDb, Long setMenuItemId, Long itemId) {
        SetMenuOneItem setMenuOneItem = getList(itemInDb.getSetMenuOneItemList()).stream().filter(p -> equals(p.getId(), setMenuItemId)).findAny().get();
        return getList(setMenuOneItem.getItemList()).stream().filter(p -> equals(p.getId(), itemId)).findAny().get();
    }

    /**
     * 计算套餐里面的其它价格
     *
     * @param itemInDb
     * @param orderItem
     * @return
     */
    public Double calSetMenuAdditionalPrice(Item itemInDb, OrderItem orderItem) throws Exception {
        double sum = 0d;
        List<SetMenuOneItem> setMenuItemList = getList(orderItem.getSetMenuOneItemList());
        for (SetMenuOneItem setMenuOneItem : setMenuItemList) {
            logger.info("cal set menu one item {}", setMenuOneItem.getId());

            //如果是不加配，那么添加不加配的钱
            if (isNoAdditionalInSetMenu(setMenuOneItem)) {
                SetMenuOneItem setMenuOneItemInDb = filterSetMenuOneItem(itemInDb, setMenuOneItem.getId());
                logger.info("add additional price {} for item {}", setMenuOneItemInDb.getAddPrice(), setMenuOneItemInDb.getId());
                sum = sum + showDouble(setMenuOneItemInDb.getAddPrice());
                continue;
            }

            //添加了其它菜，那么处理这个菜的本身的价格
            for (Item detailItem : getList(setMenuOneItem.getItemList())) {
                //如果没有传，默认为1个
                if (detailItem.getCountInOrder() == null || getInt(detailItem.getCountInOrder()) <= 0) {
                    detailItem.setCountInOrder(1);
                }

                Integer countInOrder = detailItem.getCountInOrder();

                //处理套餐里面的每一个菜的价格
                logger.info("item id {}, set menu item {} detail item id {}", itemInDb.getId(), setMenuOneItem.getId(), detailItem.getId());

                if (detailItem.getId() == null || getLong(detailItem.getId()) == 0l) {
                    SetMenuOneItem setMenuOneItemInDb = filterSetMenuOneItem(itemInDb, setMenuOneItem.getId());
                    logger.info("add additional price {} for item {}", setMenuOneItemInDb.getAddPrice(), setMenuOneItemInDb.getId());
                    sum = sum + showDouble(setMenuOneItemInDb.getAddPrice()) * countInOrder;
                    continue;
                }

                Item detailItemInDb = filterItemInSetMenu(itemInDb, setMenuOneItem.getId(), detailItem.getId());

                logger.info("add detail item set menu price {}, set menu add price {}", detailItemInDb.getId(), detailItemInDb.getSetMenuAddPrice());

                sum = sum + showDouble(detailItemInDb.getSetMenuAddPrice()) * countInOrder;

                double setMenuAddPrice = getDouble(detailItemInDb.getSetMenuAddPrice());

                //如果还传了这个菜的规格，那么添加菜的规格里面的价格
                for (ItemDetail itemDetail : getList(detailItem.getItemDetailList())) {
                    for (NameAndPrice nameAndPrice : getList(itemDetail.getNameAndPriceList())) {
                        logger.info("will add name and price {}", nameAndPrice.getId());
                        NameAndPrice nameAndPriceInDb = filterNameAndPrice(nameAndPrice.getId(), findItem(detailItem.getId()));
                        sum = sum + showDouble(nameAndPriceInDb.getPrice());
                        setMenuAddPrice = setMenuAddPrice + showMoneyDouble(nameAndPriceInDb.getPrice());
                    }
                }

                detailItem.setSetMenuAddPrice(setMenuAddPrice);
            }
        }

        return sum;
    }

    /**
     * 是否选择了不加配
     * 数组里面只有一个菜，并且ID是空的，那么就相当于选择了不加配
     *
     * @param setMenuOneItem
     * @return
     */
    public boolean isNoAdditionalInSetMenu(SetMenuOneItem setMenuOneItem) {
        List<Item> itemList = getList(setMenuOneItem.getItemList());
        if (itemList.size() != 1) {
            return false;
        }

        Item item = itemList.get(0);
        return item.getId() == null;
    }

    /**
     * 通过分类来查询商品列表
     * 后续加缓存
     *
     * @param catalogId
     * @return
     */
    public List<Item> findItemByCatalogId(Long catalogId, Boolean online) {
        CatalogItemMapping catalogItemMapping = new CatalogItemMapping();
        catalogItemMapping.setCatalogId(catalogId);
        catalogItemMapping.setOnline(online);
        List<CatalogItemMapping> catalogItemMappingList = commonService.searchAll(catalogItemMapping);
        List<Item> itemList = catalogItemMappingList.stream().map(mapping -> {
            try {
                return ItemService.getInstance().findItem(mapping.getItemId());
            } catch (Exception e) {
                logger.error("e", e);
                return null;
            }
        }).filter(p -> p != null && getBoolean(p.getEntity())).collect(Collectors.toList());

        return itemList;
    }

    /**
     * 查询该商铺下面的所有菜品
     *
     * @param shopId
     * @return
     */
    public List<Item> findItemByShopId(Long shopId) {
        Item item = new Item();
        item.setEntity(true);
        item.setShopId(shopId);
        return commonService.searchAll(item);
    }

    /**
     * 同步修改其它跟这个菜相关的套餐
     */
    public void modifyRelateSetMenuItem(Long itemId) throws Exception {
        Item item = findItem(itemId);

        List<Item> itemList = findItemByShopId(item.getShopId()).stream().filter(p -> getBoolean(p.getSetMenu())).collect(Collectors.toList());

        //只有当前修改的id，在套餐里面的时候，才会重新添加
        itemList = itemList.stream().filter(p -> setMenuItemContainTheItem(p, itemId)).collect(Collectors.toList());

        for (Item itemTmp : itemList) {
            dealSetMenuItem(itemTmp);
            commonService.save(itemTmp);
        }
    }

    /**
     * 将套餐里面的某一个菜设置成售罄
     *
     * @param item
     * @param itemId
     */
    public void setItemSaleOutInSetMenu(Item item, Long itemId) {
        item.getSetMenuOneItemList().stream().flatMap(p -> getList(p.getItemList()).stream()).filter(p -> equals(p.getId(), itemId)).forEach(p -> {
            p.setSaleOut(true);
        });
    }

    /**
     * 套餐是否已经包含了这个菜品
     *
     * @param item
     * @param itemId
     */
    public boolean setMenuItemContainTheItem(Item item, Long itemId) {
        if (!getBoolean(item.getSetMenu())) {
            logger.info("not the set menu item");
            return false;
        }

        List<SetMenuOneItem> setMenuOneItemList = getList(item.getSetMenuOneItemList());
        if (isEmpty(setMenuOneItemList)) {
            logger.info("set menu one item list is empty");
            return false;
        }

        for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
            List<Item> itemList = getList(setMenuOneItem.getItemList());
            //没有任何菜，判断下一个菜
            if (isEmpty(itemList)) {
                continue;
            }

            Optional<Item> optionalItem = itemList.stream().filter(i -> equals(i.getId(), itemId)).findAny();
            if (optionalItem.isPresent()) {
                logger.info("find the item {} in set menu item {}", itemId, item.getId());
                return true;
            }

            continue;
        }

        //最后都没有找到
        return false;
    }

    /**
     * 将相关的套餐里面，将该移除掉
     *
     * @param itemId
     */
    public void deleteRelateSetMenuItem(Long itemId) throws Exception {
        Item item = findItem(itemId);
        List<Item> itemList = findItemByShopId(item.getShopId());

        for (Item itemTmp : itemList) {
            boolean containTheItem = setMenuItemContainTheItem(itemTmp, itemId);
            //没有包含该菜品
            if (!containTheItem) {
                continue;
            }

            removeTheItemFromSetMenu(itemTmp, itemId);
            //重新处理下套餐里面的数据的值
            dealSetMenuItem(itemTmp);
            //过滤SetMenuItem里面空itemList
            filterNullItemList(itemTmp);
            commonService.save(itemTmp);
        }
    }

    /**
     * 将菜品从套餐里面移除
     *
     * @param item
     */
    public void removeTheItemFromSetMenu(Item item, Long itemId) {
        List<SetMenuOneItem> setMenuOneItemList = getList(item.getSetMenuOneItemList());
        for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
            List<Item> itemList = getList(setMenuOneItem.getItemList());
            setMenuOneItem.setItemList(itemList.stream().filter(i -> !equals(i.getId(), itemId)).collect(Collectors.toList()));
        }
    }

    /**
     * 计算每一个菜的实时价格
     *
     * @param item
     */
    public void setRealTimePrice(Item item) throws Exception {
        if (item.getPrice() != null && item.getPrice() > 0) {
            logger.info("item all time the same price, item is {}", item.getId());
            return;
        }

        SceneService sceneService = SceneService.getInstance();
        //根据当前时间的场景值来设置价格
        for (PriceConfig priceConfig : item.getPriceConfigList()) {
            Long sceneId = priceConfig.getSceneId();

            //如果传了过滤的场景值，那么以过滤的场景值为准，不用关心场景值是否是当前的时间段
            if (item.getFilterSceneId() != null && item.getFilterSceneId() != 0) {
                logger.info("filter sceneId is {}", item.getFilterSceneId());
                if (equals(item.getFilterSceneId(), sceneId)) {
                    logger.info("find the filter sceneId", sceneId);
                    item.setPrice(priceConfig.getPrice());
                    return;
                }
            } else {
                Scene scene = sceneService.findScene(sceneId);
                boolean matchTime = sceneService.isMatchTime(scene);

                if (matchTime) {
                    logger.info("scene {} match the current time, item is {}", scene.getId(), item.getId());
                    item.setPrice(priceConfig.getPrice());
                    return;
                } else {
                    logger.info("sceneId {} is not match the current time", scene.getId());
                }
            }
        }

        logger.info("item {} can not find the match time", item.getId());
        //如果没有找到，则将价格设置成负数
        item.setPrice(Constant.INVALID_ITEM_PRICE);
    }

    /**
     * 批量设置实时价格
     *
     * @param itemList
     * @throws Exception
     */
    public void setItemListWithRealTimePrice(List<Item> itemList) throws Exception {
        if (isEmpty(itemList)) {
            logger.info("item list is empty");
            return;
        }

        for (Item item : itemList) {
            setRealTimePrice(item);
        }
    }

    /**
     * 过滤价格是合法的菜品
     *
     * @param itemList
     * @return
     */
    public List<Item> filterValidPriceItemList(List<Item> itemList) {
        if (isEmpty(itemList)) {
            logger.info("item list is empty");
            return new ArrayList<Item>();
        }

        logger.info("before filter size is {}", itemList.size());
        List<Item> filterItemList = itemList.stream().filter(item -> getBoolean(item.getRealPriceItem())
                || (item.getPrice() != null && item.getPrice() >= 0)).collect(Collectors.toList());

        if (filterItemList.size() != itemList.size()) {
            logger.info("item list is {}", StringUtils.join(itemList, ","));
        }

        return filterItemList;
    }

    /**
     * 商品的名称同步到映射关系里面
     *
     * @param itemId
     */
    public void itemNameSyncToOther(Long itemId) throws Exception {
        Item item = findItem(itemId);
        CatalogItemMapping catalogItemMapping = new CatalogItemMapping();
        catalogItemMapping.setItemId(itemId);
        List<CatalogItemMapping> catalogItemMappings = commonService.searchAll(catalogItemMapping);

        //依次保存
        for (CatalogItemMapping itemMapping : catalogItemMappings) {
            itemMapping.setItemName(item.getName());
            itemMapping.setItemName_zh(item.getName_zh());
            itemMapping.setItemName_en(item.getName_en());
            commonService.save(itemMapping);
        }
    }

    /**
     * 修改套餐里面的名称
     *
     * @param itemInDb
     */
    public void syncItemNameInSetMenu(Item itemInDb) throws Exception {
        List<Item> itemList = findItemByShopId(itemInDb.getShopId());
        List<Item> setMenuItemList = itemList.stream().filter(setMenuItem -> setMenuItemContainTheItem(setMenuItem, itemInDb.getId())).collect(Collectors.toList());

        for (Item setMenuItem : setMenuItemList) {
            for (SetMenuOneItem setMenuOneItem : setMenuItem.getSetMenuOneItemList()) {
                List<Item> itemListInSetMenu = setMenuOneItem.getItemList();
                Optional<Item> itemOptional = itemListInSetMenu.stream().filter(p -> equals(p.getId(), itemInDb.getId())).findAny();
                if (itemOptional.isPresent()) {
                    Item item = itemOptional.get();
                    logger.info("find the item {} in setMenu {}", itemInDb.getId(), setMenuItem.getId());
                    BeanUtils.copyProperties(itemInDb, item, "price", "setMenuAddPrice");
                }
            }

            commonService.save(setMenuItem);
        }
    }

    /**
     * 修改菜品的顺序
     *
     * @param item
     * @throws Exception
     */
    public void modifyItemShowOrder(Item item) throws Exception {
        Long itemId = item.id;
        Item itemInDb = findItem(itemId);

        CatalogItemMapping catalogItemMapping = new CatalogItemMapping();
        catalogItemMapping.setItemId(item.getId());
        catalogItemMapping.setEntity(true);

        Optional<CatalogItemMapping> catalogItemMappingOptional = commonService.searchOneOptional(catalogItemMapping);

        if (catalogItemMappingOptional.isPresent() && !getBoolean(item.getSuggestion())) {
            CatalogItemMapping itemMapping = catalogItemMappingOptional.get();

            List<CatalogItemMapping> mappingList = MappingService.getInstance().findCatalogItemMappingByCatalog(itemMapping.getCatalogId());
            List<Item> itemList = ItemService.getInstance().findItemByItemList(mappingList.stream().map(p -> p.getItemId()).collect(Collectors.toList()));
            resetItemShowOrder(item, itemList);
        }

        //如果还是推荐菜，那么修改推荐菜的显示顺序
        if (getBoolean(itemInDb.getSuggestion())) {
            List<Item> allSuggestionItem = findAllSuggestionItem(itemInDb.getShopId(), null);
            resetItemSuggestionShowOrder(itemInDb, allSuggestionItem);
        }
    }

    /**
     * 重新修复菜品的顺序
     *
     * @param item
     * @param itemList
     * @throws Exception
     */
    private void resetItemShowOrder(Item item, List<Item> itemList) throws Exception {
        logger.info("item list size is {}", itemList.size());
        Integer itemShowOrder = item.getShowOrder();
        List<Item> sameOrderItemList = itemList.stream().filter(p -> getInt(p.getShowOrder()) == itemShowOrder.intValue() && p.id.longValue() != item.id.longValue()).collect(Collectors.toList());
        logger.info("sameOrderItemList size is {}", sameOrderItemList.size());

        //如果有相同顺序的菜品，那么所有大于等于菜的顺序均加1
        if (isNotEmpty(sameOrderItemList)) {
            List<Item> modifyItemList = itemList.stream().filter(p -> getInt(p.getShowOrder()) >= itemShowOrder && p.id.longValue() != item.id.longValue()).collect(Collectors.toList());
            logger.info("modifyItemList size is {}", modifyItemList.size());

            for (Item modifyItem : modifyItemList) {
                modifyItem.setShowOrder(modifyItem.getShowOrder() + 1);
                logger.info("will modify item {} show order", modifyItem.getId());
                commonService.save(modifyItem);
            }
        }
    }

    /**
     * 重新修改推荐菜的顺序
     *
     * @param item
     * @param itemList
     * @throws Exception
     */
    private void resetItemSuggestionShowOrder(Item item, List<Item> itemList) throws Exception {
        logger.info("item list size is {}", itemList.size());
        List<Item> sameOrderItemList = itemList.stream().filter(p -> equals(p.getSuggestShowOrder(), item.getSuggestShowOrder()) && p.id.longValue() != item.id.longValue()).collect(Collectors.toList());
        logger.info("find the same order item list");

        //如果有相同顺序的菜品，那么所有大于等于菜的顺序均加1
        if (isNotEmpty(sameOrderItemList)) {
            List<Item> modifyItemList = itemList.stream().filter(p -> getInt(p.getSuggestShowOrder()) >= item.getSuggestShowOrder() && p.id.longValue() != item.id.longValue()).collect(Collectors.toList());

            for (Item modifyItem : modifyItemList) {
                modifyItem.setSuggestShowOrder(modifyItem.getSuggestShowOrder() + 1);
                logger.info("will modify item {} suggestion show order", modifyItem.getId());
                commonService.save(modifyItem);
            }
        }
    }

    /**
     * 产生一个索引
     *
     * @return
     * @throws Exception
     */
    public Long generateItemIndex() throws Exception {
        ItemDetailIndex itemDetailIndex = new ItemDetailIndex();
        commonService.createObject(itemDetailIndex);
        return itemDetailIndex.getId();
    }

    /**
     * 给菜品添加索引
     *
     * @param item
     */
    public void addDetailIndex(Item item) throws Exception {
        logger.info("will add detail index");
        List<ItemDetail> itemDetailList = item.getItemDetailList();

        if (isEmpty(itemDetailList)) {
            logger.info("item detail list is empty");
            return;
        }

        //规格项ID如果是空，那么将添加ID
        for (ItemDetail itemDetail : itemDetailList) {
            if (itemDetail.getId() == null) {
                logger.info("will add detail  index {}", itemDetail);
                itemDetail.setId(generateItemIndex());
                //并做国际化处理
                ZhEnService.getInstance().dealZhEn(itemDetail);
            }

            //再判断细节部分
            //细节项如果为空，那么将添加ID
            List<NameAndPrice> nameAndPriceList = itemDetail.getNameAndPriceList();
            if (isNotEmpty(nameAndPriceList)) {
                for (NameAndPrice nameAndPrice : nameAndPriceList) {
                    if (nameAndPrice.getId() == null) {
                        logger.info("will add name and price list index {}", nameAndPrice);
                        nameAndPrice.setId(generateItemIndex());
                        //并做国际化处理
                        ZhEnService.getInstance().dealZhEn(nameAndPrice);
                    }
                }
            } else {
                logger.info("item detail do not have the name and price list {}", itemDetail);
            }
        }
    }

    /**
     * 判断菜品的名称是否修改了
     *
     * @param item
     * @return
     */
    public boolean isModifyName(Item item) {
        return isNotEmpty(item.getName()) || isNotEmpty(item.getName_zh()) || isNotEmpty(item.getName_en());
    }

    /**
     * 处理菜品的国际化问题
     *
     * @param item
     */
    public void dealItemZhEn(Item item) throws IllegalAccessException {
        //先序列化，然后依次按照属性国际化
        commonService.dealFieldMapping(item, true);
        ZhEnService zhEnService = ZhEnService.getInstance();

        //有一个语言为空的时候，做特殊处理
        if (isEmpty(item.getName_zh()) || isEmpty(item.getName_en())) {
            zhEnService.dealZhEn(item);
        }

        //处理细节
        List<ItemDetail> itemDetailList = item.getItemDetailList();
        if (isNotEmpty(itemDetailList)) {
            for (ItemDetail itemDetail : itemDetailList) {
                //有一个语言为空的时候，做特殊处理
                if (isEmpty(itemDetail.getName_zh()) || isEmpty(itemDetail.getName_en())) {
                    zhEnService.dealZhEn(itemDetail);
                }

                //再设置下细节
                List<NameAndPrice> nameAndPriceList = itemDetail.getNameAndPriceList();

                if (isNotEmpty(nameAndPriceList)) {
                    for (NameAndPrice nameAndPrice : nameAndPriceList) {
                        //有一个语言为空的时候，做特殊处理
                        if (isEmpty(nameAndPrice.getName_zh()) || isEmpty(nameAndPrice.getName_en())) {
                            zhEnService.dealZhEn(nameAndPrice);
                        }
                    }
                }
            }
        } else {
            logger.info("item not have the detail list");
        }

        //处理新版本套餐
        if (isNotEmpty(item.getSetMenuOneItemList())) {
            List<SetMenuOneItem> setMenuOneItemList = item.getSetMenuOneItemList();
            for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
                //有一个为空的时候才处理
                if (isEmpty(setMenuOneItem.getCatalog_en()) || isEmpty(setMenuOneItem.getCatalog_zh())) {
                    zhEnService.dealZhEn(setMenuOneItem);
                }
            }
        }
    }

    /**
     * 标签的国际化处理
     *
     * @param item
     */
    public void labelListZhEn_create(Item item) {
        //如果中英文均存在，则不处理
        if (isNotEmpty(item.getLabelEnList()) && isNotEmpty(item.getLabelEnList())) {
            return;
        }

        //如果中文存在，英文不存在，则复制
        if (isNotEmpty(item.getLabelZhList()) && isEmpty(item.getLabelEnList())) {
            item.setLabelEnList(item.getLabelZhList());
        } else if (isNotEmpty(item.getLabelEnList()) && isEmpty(item.getLabelZhList())) {
            //如果英文存在，中文不存在，则复制
            item.setLabelZhList(item.getLabelEnList());
        }
    }

    /**
     * 介绍的中英文处理
     *
     * @param item
     */
    public void descriptionZhEn_create(Item item) {
        if (isNotEmpty(item.getDescription_zh()) && isNotEmpty(item.getDescription_en())) {
            return;
        }

        //如果中文存在，英文不存在，则复制
        if (isNotEmpty(item.getDescription_zh()) && isEmpty(item.getDescription_en())) {
            item.setDescription_en(item.getDescription_zh());
        } else if (isNotEmpty(item.getDescription_en()) && isEmpty(item.getDescription_zh())) {
            //如果英文存在，中文不存在，则复制
            item.setDescription_zh(item.getDescription_en());
        }
    }

    /**
     * 过滤商品详情
     *
     * @param itemDetailId
     * @param item
     * @return
     * @throws ResponseStatusException
     */
    public ItemDetail filterItemDetail(Long itemDetailId, Item item) throws ResponseStatusException {
        VerifyUtil.verify(() -> itemDetailId != null, ResponseStatus.CONFIG_WRONG);

        List<ItemDetail> itemDetailList = item.getItemDetailList();
        if (isEmpty(itemDetailList)) {
            VerifyUtil.throwError(ResponseStatus.CONFIG_WRONG);
        }

        Optional<ItemDetail> itemDetailOptional = itemDetailList.stream().filter(p -> equals(p.getId(), itemDetailId)).findFirst();
        if (!itemDetailOptional.isPresent()) {
            VerifyUtil.throwError(ResponseStatus.CONFIG_WRONG);
        }

        return itemDetailOptional.get();
    }

    /**
     * 过滤出细节
     *
     * @param nameAndPriceId
     * @param itemDetail
     * @return
     */
    public NameAndPrice filterNameAndPrice(Long nameAndPriceId, ItemDetail itemDetail) throws ResponseStatusException {
        VerifyUtil.verify(() -> nameAndPriceId != null, ResponseStatus.CONFIG_WRONG);

        List<NameAndPrice> nameAndPriceList = itemDetail.getNameAndPriceList();
        if (isEmpty(nameAndPriceList)) {
            VerifyUtil.throwError(ResponseStatus.CONFIG_WRONG);
        }

        Optional<NameAndPrice> nameAndPriceOptional = nameAndPriceList.stream().filter(p -> equals(nameAndPriceId, p.getId())).findFirst();
        if (!nameAndPriceOptional.isPresent()) {
            VerifyUtil.throwError(ResponseStatus.CONFIG_WRONG);
        }

        return nameAndPriceOptional.get();
    }

    /**
     * 过滤出规格项
     *
     * @param nameAndPriceId
     * @param itemInDb
     * @return
     */
    public NameAndPrice filterNameAndPrice(Long nameAndPriceId, Item itemInDb) throws ResponseStatusException {
        VerifyUtil.verify(() -> nameAndPriceId != null, ResponseStatus.CONFIG_WRONG);
        List<ItemDetail> itemDetailList = itemInDb.getItemDetailList();
        VerifyUtil.verify(() -> isNotEmpty(itemDetailList), ResponseStatus.CONFIG_WRONG);
        List<NameAndPrice> allNameAndPriceList = itemDetailList.stream().flatMap(p -> p.getNameAndPriceList().stream()).collect(Collectors.toList());
        Optional<NameAndPrice> nameAndPriceOptional = allNameAndPriceList.stream().filter(p -> equals(p.getId(), nameAndPriceId)).findFirst();

        if (!nameAndPriceOptional.isPresent()) {
            VerifyUtil.throwError(ResponseStatus.CONFIG_WRONG);
        }

        return nameAndPriceOptional.get();
    }

    /**
     * 将菜品相关的套餐也设置成售罄
     *
     * @param item
     * @throws Exception
     */
    public void setSetMenuSaleOut(Item item) throws Exception {
        Item itemInDb = findItem(item.getId());

        if (getBoolean(itemInDb.getSetMenu())) {
            logger.info("do not deal set menu item");
            return;
        }

        //查询所有的套餐，不管是否已经上线
        List<Item> setMenuList = findSetMenuItem(itemInDb.getShopId(), null);

        //过滤出包含菜品的套餐
        setMenuList = setMenuList.stream().filter(setMenu -> setMenuItemContainTheItem(setMenu, item.getId())).collect(Collectors.toList());

        //依次在每个套餐里面，将菜品设置成售罄
        for (Item setMenuItem : setMenuList) {
            setItemSaleOutInSetMenu(setMenuItem, item.getId());
        }

        //依次售罄
        for (Item setMenuItem : setMenuList) {
            if (canSetMenuSaleOut(setMenuItem)) {
                logger.info("set menu {} sale out", setMenuItem.getId());
                setMenuItem.setSaleOut(true);

                //同步修改映射关系
                List<CatalogItemMapping> itemMappingList = MappingService.getInstance().findCatalogItemMappingByItem(setMenuItem.getId());
                for (CatalogItemMapping catalogItemMapping : itemMappingList) {
                    catalogItemMapping.setSaleOut(true);
                    commonService.save(catalogItemMapping);
                }

                commonService.save(setMenuItem);
            }
        }
    }

    /**
     * 判断套餐是否需要标记成售罄
     *
     * @param item
     * @return
     */
    public boolean canSetMenuSaleOut(Item item) {
        for (SetMenuOneItem setMenuOneItem : getList(item.getSetMenuOneItemList())) {
            //只有一个固定菜，并且售罄
            if (getBoolean(setMenuOneItem.getFixed()) && getList(setMenuOneItem.getItemList()).size() == 1 && getBoolean(getList(setMenuOneItem.getItemList()).get(0).getSaleOut())) {
                return true;
            }

            //某一个选项里面的所有菜都售罄了
            List<Item> itemList = getList(setMenuOneItem.getItemList());
            if (itemList.isEmpty()) {
                continue;
            }

            //不加配的情况 ，再判断是否所有的菜都售罄了
            if (!getBoolean(setMenuOneItem.getAddAdditional())) {
                if (itemList.stream().allMatch(p -> getBoolean(p.getSaleOut()))) {
                    return true;
                }
            }

            continue;
        }

        return false;
    }

    /**
     * 从菜品集合中过滤一个菜
     *
     * @param itemList
     * @return
     */
    public Optional<Item> filterItem(List<Item> itemList, Long itemId) {
        return itemList.stream().filter(p -> equals(p.getId(), itemId)).findFirst();
    }

    /**
     * 将套餐下面的所有菜均显示
     *
     * @param item
     * @return
     */
    public List<Item> filterItemListInSetMenu(Item item) {
        if (!getBoolean(item.getSetMenu())) {
            logger.info("not set menu item");
            return new ArrayList<>();
        }

        List<SetMenuOneItem> setMenuOneItemList = item.getSetMenuOneItemList();
        if (isEmpty(setMenuOneItemList)) {
            logger.info("set menu one item list is emtpy");
            return new ArrayList<>();
        }

        List<Item> itemList = setMenuOneItemList.stream().flatMap(p -> getList(p.getItemList()).stream()).collect(Collectors.toList());

        return itemList;
    }

    /**
     * 如果菜品恢复可售，那么检查下对应的套餐是否可以恢复
     * 恢复的条件是套餐下面所有的菜均可售
     *
     * @param item
     */
    public void restoreSetMenuSaleOut(Item item) throws Exception {
        Item itemInDb = findItem(item.getId());

        if (getBoolean(itemInDb.getSetMenu())) {
            logger.info("do not deal set menu");
            return;
        }

        //查询所有的套餐，不管是否已经上线
        List<Item> setMenuList = findSetMenuItem(itemInDb.getShopId(), null);

        //过滤出包含菜品的套餐
        setMenuList = setMenuList.stream().filter(p -> {
            return setMenuItemContainTheItem(p, item.getId());
        }).collect(Collectors.toList());

        List<Item> allItemList = findItemByShopId(itemInDb.getShopId());
        logger.info("setMenuList size is {}", setMenuList.size());

        //先过滤出包含该菜的套餐
        List<Item> setMenuItemList = allItemList.stream().filter(p -> setMenuItemContainTheItem(p, item.getId())).collect(Collectors.toList());

        for (Item setMenuItem : setMenuItemList) {
            List<Item> itemList = getList(setMenuItem.getSetMenuOneItemList()).stream().flatMap(p -> getList(p.getItemList()).stream()).filter(p -> equals(p.getId(), item.getId())).collect(Collectors.toList());
            for (Item tmpItem : itemList) {
                tmpItem.setSaleOut(false);
            }
        }

        for (Item setMenuItem : setMenuItemList) {
            //判断是否售罄，如果售罄写售罄标记，如果没有售罄，写没有售罄标记
            if (canSetMenuSaleOut(setMenuItem)) {
                setMenuItem.setSaleOut(true);
            } else {
                setMenuItem.setSaleOut(false);
            }
            commonService.save(setMenuItem);

            //如果是已恢复，那么同步修改映射关系
            if (!getBoolean(setMenuItem.getSaleOut())) {
                List<CatalogItemMapping> mapplist = MappingService.getInstance().findCatalogItemMappingByItem(setMenuItem.getId());
                for (CatalogItemMapping catalogItemMapping : mapplist) {
                    catalogItemMapping.setSaleOut(false);
                    commonService.save(catalogItemMapping);
                }
            }
        }
    }

    /**
     * 通过菜品来查询品类
     *
     * @param item
     * @return
     */
    public Optional<Catalog> findCatalog(Item item) {
        if (item == null) {
            return Optional.empty();
        }

        if (item.getCatalogId() != null) {
            return CatalogService.getInstance().findCatalog(item.getCatalogId());
        }

        List<CatalogItemMapping> mappingList = MappingService.getInstance().findCatalogItemMappingByItem(item.getId());
        if (isEmpty(mappingList)) {
            return Optional.empty();
        }

        CatalogItemMapping catalogItemMapping = mappingList.get(0);
        Long catalogId = catalogItemMapping.getCatalogId();
        return CatalogService.getInstance().findCatalog(catalogId);
    }

    /**
     * 推荐菜的过滤办法
     *
     * @param filterSceneId
     * @param itemList
     * @return
     */
    public List<Item> filterAllTimeSceneList(Long filterSceneId, List<Item> itemList) {
        return itemList.stream().filter(item -> {
            return getBoolean(item.getOnline());
        }).filter(item -> {
            //推荐菜在该场景下面推荐了
            List<NameAndId> sceneList = item.getSceneList();
            if (isEmpty(sceneList)) {
                logger.info("none sugguest scene");
                return false;
            }

            return sceneList.stream().map(p -> p.getId()).filter(id -> equals(id, filterSceneId)).findAny().isPresent();
        }).filter(item -> {
            //推荐菜的时间是否在当前时间范围内
            Long catalogId = item.getCatalogId();
            Optional<Catalog> catalogOptional = CatalogService.getInstance().findCatalog(catalogId);
            if (!catalogOptional.isPresent()) {
                logger.info("can not find the catalog");
                return false;
            }

            Catalog catalog = catalogOptional.get();

            //按照场景来匹配
            if (isNotEmpty(catalog.getSceneList())) {
                return catalog.getSceneList().stream().map(p -> p.getId()).filter(id -> equals(id, filterSceneId)).findAny().isPresent();
            }

            //按照指定时间段来匹配
            List<TimeConfig> timeConfigList = catalog.getTimeConfigList();
            if (isEmpty(timeConfigList)) {
                logger.info("time config is empty");
                return false;
            }

            TimeConfig timeConfig = timeConfigList.get(0);
            return SceneService.getInstance().inTimeRange(timeConfig.getStartTime(), timeConfig.getEndTime(), System.currentTimeMillis());
        }).collect(Collectors.toList());
    }

    /**
     * 过滤菜品
     *
     * @param getFilterSceneId
     * @param itemList
     * @return
     */
    public List<Item> filterItemSceneList(Long getFilterSceneId, List<Item> itemList) {
        if (getFilterSceneId == null) {
            logger.info("nothing filter");
            return itemList;
        } else {
            List filterItemList = new ArrayList<Item>();

            //时价菜处理
            List<Item> realPriceItemList = itemList.stream().filter(item -> getBoolean(item.getRealPriceItem())).
                    filter(item -> getBoolean(item.getOnline()))
                    .filter(item -> {
                        //如果有场景价格，必须打开
                        if (isEmpty(item.getPriceConfigList())) {
                            return true;
                        }

                        Optional<PriceConfig> priceConfigOptional = item.getPriceConfigList().stream().filter(priceConfig -> equals(priceConfig.getSceneId(), getFilterSceneId)).findAny();
                        //没有找到场景
                        if (!priceConfigOptional.isPresent()) {
                            return false;
                        }

                        //找到了，还必须打开
                        return getBoolean(priceConfigOptional.get().getEnable());
                    })
                    .filter(item -> {
                        //再判断该菜绑定的品类的时间
                        Optional<Catalog> catalogOptional = findCatalog(item);
                        if (!catalogOptional.isPresent()) {
                            logger.info("can  not find the catalog");
                            return false;
                        }

                        Catalog catalog = catalogOptional.get();

                        try {
                            return CatalogService.getInstance().isCatalogInSceneTime(getFilterSceneId, catalog);
                        } catch (Exception e) {
                            logger.error("e", e);
                            return false;
                        }
                    }).collect(Collectors.toList());
            filterItemList.addAll(realPriceItemList);

            //开始过滤菜品,菜品包含该场景，并且该场景是开启状态
            //如果没有配置场景，并且价格大于0，就是全场景
            List<Item> allSceneList = itemList.stream().filter(item -> !getBoolean(item.getRealPriceItem())).filter(item -> {
                //这里是没有场景的菜的匹配规则
                boolean basicConfig = isEmpty(item.getPriceConfigList()) && getDouble(item.getPrice()) > 0;
                if (!basicConfig) {
                    logger.info("item {} not the time item, setmenu {}, price {}, price config list {}", item.getId(), getBoolean(item.getSetMenu()), item.getPrice(), item.getPriceConfigList());
                    return false;
                }

                if (!getBoolean(item.getOnline())) {
                    return false;
                }

                //再判断该菜绑定的品类的时间
                Optional<Catalog> catalogOptional = findCatalog(item);
                if (!catalogOptional.isPresent()) {
                    logger.info("can  not find the catalog");
                    return false;
                }

                Catalog catalog = catalogOptional.get();

                try {
                    return CatalogService.getInstance().isCatalogInSceneTime(getFilterSceneId, catalog);
                } catch (Exception e) {
                    logger.error("e", e);
                    return false;
                }
            }).collect(Collectors.toList());
            logger.info("allSceneList size is {}", allSceneList.size());
            filterItemList.addAll(allSceneList);

            List<Item> sceneFilterList = itemList.stream().filter(item -> !getBoolean(item.getRealPriceItem())).filter(item -> isNotEmpty(item.getPriceConfigList())).filter(item -> {
                List<PriceConfig> priceConfigList = item.getPriceConfigList();
                List<PriceConfig> enableConfigList = priceConfigList.stream().filter(config -> equals(config.getSceneId(), getFilterSceneId) && getBoolean(config.getEnable())).collect(Collectors.toList());
                boolean filterResult = isNotEmpty(enableConfigList);
                logger.info("scene item {} filter result {}", item.getId(), filterResult);
                return filterResult;
            }).collect(Collectors.toList());

            filterItemList.addAll(sceneFilterList);
            logger.info("sceneFilterList size is {}", sceneFilterList.size());

            return filterItemList;
        }
    }

    /**
     * 如果传了价格设置，那么每个的场景值一定不相等
     *
     * @param item
     */
    public void checkPriceConfigValid(Item item) throws ResponseStatusException {
        if (isEmpty(item.getPriceConfigList())) {
            return;
        }

        List<PriceConfig> priceConfigList = item.getPriceConfigList();
        List<Long> sceneIdList = priceConfigList.stream().map(p -> p.getSceneId().longValue()).collect(Collectors.toList());
        VerifyUtil.verify(() -> sceneIdList.size() == priceConfigList.size());
    }

    /**
     * 检查细节长度
     *
     * @param item
     */
    public void checkItemDetailLength(Item item) throws ResponseStatusException {
        List<ItemDetail> itemDetailList = item.getItemDetailList();
        if (isEmpty(itemDetailList)) {
            logger.info("itemDetailList is empty");
            return;
        }

        List<NameAndPrice> nameAndPriceList = itemDetailList.stream().flatMap(p -> getList(p.getNameAndPriceList()).stream()).collect(Collectors.toList());
        int max_size = 70;
        VerifyUtil.verify(() -> nameAndPriceList.size() <= max_size, ResponseStatus.NAME_AND_PRICE_LENGTH_MORE_THAN_50, max_size);
    }

    /**
     * 计算可用的库存
     *
     * @param item
     */
    public void calItemAvailableItem(Item item) {
        if (item == null) {
            logger.info("item is null");
            return;
        }

        Integer leftCount = item.getLeftCount();
        if (leftCount == null) {
            logger.info("do not set the left count {}", item.getId());
            return;
        }

        int availableCount = leftCount - getInt(item.getLockCount());
        item.setAvailableCount(availableCount);
    }

    /**
     * 计算当次要减少的库存数量
     *
     * @param stock
     */
    public void calItemCutNumber(Stock stock) {
        if (stock == null) {
            logger.info("stock is null");
            return;
        }

        if (stock.getLeftCount() != null) {
            stock.setCutItemCount(stock.getLeftCount());
            return;
        }

        if (stock.getLockCount() != null) {
            stock.setCutItemCount(stock.getLockCount());
            return;
        }

        logger.info("can not find the cut item count {}", stock.getItemId());
    }

    /**
     * 统计所有在线的菜品
     *
     * @return
     */
    public long countAllOnlineItem() {
        ItemDao itemDao = BeanUtil.getBean(ItemDao.class);
        long countOnlineItem = itemDao.countOnlineItem(true, true, false);
        return countOnlineItem;
    }

    /**
     * 计算上线的数量
     *
     * @param catalogId
     * @return
     */
    public long countCatalogOnline(Long catalogId) {
        Item item = new Item();
        item.setEntity(true);
        item.setCatalogId(catalogId);
        item.setOnline(true);
        item.setFlagDelete(false);
        return commonService.count(item);
    }

    /**
     * 过滤套餐里面的某一项
     *
     * @param itemInDb
     * @param setMenuOneItemId
     * @return
     */
    public SetMenuOneItem filterSetMenuOneItem(Item itemInDb, Long setMenuOneItemId) {
        return getList(itemInDb.getSetMenuOneItemList()).stream().filter(p -> equals(p.getId(), setMenuOneItemId)).findAny().get();
    }


    /**
     * 处理套餐里面的每一项菜品
     *
     * @param wholeItem
     */
    public void dealSetMenuItem(Item wholeItem) throws Exception {
        if (!getBoolean(wholeItem.getSetMenu())) {
            logger.info("not the set menu item");
            return;
        }

        List<SetMenuOneItem> setMenuOneItemList = wholeItem.getSetMenuOneItemList();
        if (isEmpty(setMenuOneItemList)) {
            logger.info("set menu item list is empty");
            return;
        }

        //套餐里面的每一项
        for (SetMenuOneItem setMenuOneItem : wholeItem.getSetMenuOneItemList()) {
            List<Item> itemList = setMenuOneItem.getItemList();
            //套餐里面的每一项
            for (Item item : itemList) {
                Item itemInDb = findItem(item.getId());
                //将数据库里面的数据写到请求里面来
                BeanUtils.copyProperties(itemInDb, item, "setMenuAddPrice");
            }

            if (setMenuOneItem.getId() == null) {
                logger.info("will create item catalog id");
                //如果是套餐，套餐里面的标签ID唯一生成
                Long itemCatalogId = OrderService.getInstance().generateOrderItemId(wholeItem.getShopId());
                setMenuOneItem.setId(itemCatalogId);
            }
        }
    }

    /**
     * 通过品类查询菜品
     *
     * @param catalogIdList
     * @return
     */
    public List<Long> findItemByCatalogList(List<Long> catalogIdList) {
        return catalogIdList.stream().map(catalogId -> {
            return findItemByCatalogId(catalogId, null).stream().map(p -> p.getId()).collect(Collectors.toList());
        }).flatMap(p -> p.stream()).collect(Collectors.toList());
    }

    /**
     * 向菜品里面添加场景
     *
     * @param item
     * @param sceneId
     */
    public void addScene(Item item, Long sceneId) throws Exception {
        List<PriceConfig> priceConfigList = item.getPriceConfigList();
        PriceConfig priceConfig = new PriceConfig();
        priceConfig.setSceneId(sceneId);
        priceConfig.setPrice(0d);
        priceConfig.setEnable(false);
        Scene scene = SceneService.getInstance().findScene(sceneId);
        priceConfig.setSceneName(scene.getName());
        priceConfigList.add(priceConfig);
        commonService.save(item);

    }

    /**
     * 将场景ID从菜品里面删除
     *
     * @param item
     * @param sceneId
     */
    public void cutScene(Item item, Long sceneId) throws Exception {
        List<PriceConfig> priceConfigList = getList(item.getPriceConfigList());
        priceConfigList = priceConfigList.stream().filter(p -> !equals(p.getSceneId(), sceneId)).collect(Collectors.toList());
        item.setPriceConfigList(priceConfigList);
        commonService.save(item);
    }

    /**
     * 通过主菜ID查询所有的菜
     *
     * @param companyId
     * @param mainItemId
     * @return
     */
    public List<Item> findAllItemByCompanyMainItemId(Long companyId, Long mainItemId) {
        Item item = new Item();
        item.setCompanyId(companyId);
        item.setMainItemId(mainItemId);
        return commonService.searchAll(item);
    }

    /**
     * 通过公司ID查询所有的商品
     *
     * @param companyId
     * @return
     */
    public List<Item> findAllItemByCompanyId(Long companyId) {
        Item item = new Item();
        item.setCompanyId(companyId);
        item.setEntity(true);
        return commonService.searchAll(item);
    }


    /**
     * 品类下面的菜，按照顺序排序
     *
     * @param catalogItemMappingList
     */
    public void sortItem(List<CatalogItemMapping> catalogItemMappingList) {
        List<Long> itemIdList = catalogItemMappingList.stream().map(p -> p.getItemId()).collect(Collectors.toList());
        List<Item> itemList = findItemByItemList(itemIdList);

        //排序
        catalogItemMappingList.sort(new Comparator<CatalogItemMapping>() {
            @Override
            public int compare(CatalogItemMapping o1, CatalogItemMapping o2) {
                Optional<Item> item1 = filterItem(itemList, o1.getItemId());
                Optional<Item> item2 = filterItem(itemList, o2.getItemId());
                if (!item1.isPresent()) {
                    return 1;
                }

                if (!item2.isPresent()) {
                    return 1;
                }

                return getInt(item1.get().getShowOrder()) - getInt(item2.get().getShowOrder());
            }
        });
    }

    /**
     * 计算菜品在订单里面的价格
     *
     * @param item
     * @return
     */
    public Double calItemInSetMenuPrice(Item item) {
        int count = calItemCountInSetMenu(item);

        return getDouble(item.getSetMenuAddPrice()) * count;
    }

    /**
     * 获取菜在套餐里面的数量
     *
     * @param item
     * @return
     */
    public int calItemCountInSetMenu(Item item) {
        Integer count = getInt(item.getCountInOrder());
        if (count <= 0) {
            count = 1;
        }

        return count;
    }

    /**
     * 如果有场景价格，只保留场景价格
     *
     * @param itemInDb
     */
    public void onlyOnePrice(Item itemInDb) throws Exception {
        //如果设置了场景的价格，那么统一价格就不再设置了
        if (isNotEmpty(itemInDb.getPriceConfigList()) && itemInDb.getPrice() != null) {
            logger.info("will modify price to null");
            itemInDb.setPrice(null);
            commonService.save(itemInDb);
        }
    }

    /**
     * 验证名称长度
     *
     * @param item
     */
    public void validItemName(Item item) throws ResponseStatusException {
        if (isNotEmpty(item.getName())) {
            VerifyUtil.verify(() -> item.getName().length() <= 128, ResponseStatus.ITEM_LENGTH_TOO_LONG);
        }

        if (isNotEmpty(item.getName_zh())) {
            VerifyUtil.verify(() -> item.getName_zh().length() <= 128, ResponseStatus.ITEM_LENGTH_TOO_LONG);
        }

        if (isNotEmpty(item.getName_en())) {
            VerifyUtil.verify(() -> item.getName_en().length() <= 128, ResponseStatus.ITEM_LENGTH_TOO_LONG);
        }

    }

    /**
     * 是否有相同的场景价格
     *
     * @param item
     */
    public boolean hasSameScenePrice(Item item) {
        logger.info("item is {}", item.getId());

        List<PriceConfig> priceConfigList = item.getPriceConfigList();
        if (isEmpty(priceConfigList)) {
            logger.info("not config price scene");
            return false;
        }

        if (priceConfigList.size() <= 1) {
            logger.info("only one price scene");
            return false;
        }

        //如果场景的价格数量与价格的数量不一致，那么存在两个相同的场景价格
        Set<Long> sceneSet = priceConfigList.stream().map(priceConfig -> priceConfig.getSceneId()).collect(Collectors.toSet());
        return sceneSet.size() != priceConfigList.size();
    }

    /**
     * 该菜品对应的品类是有场景值的，也就是说菜品不应该有固定价格
     *
     * @param item
     * @return
     */
    public boolean isSceneItem(Item item) {
        Long catalogId = item.getCatalogId();
        if (catalogId == null) {
            logger.info("do not has catalog id");
            return false;
        }

        Optional<Catalog> catalogOptional = CatalogService.getInstance().findCatalog(catalogId);
        if (!catalogOptional.isPresent()) {
            logger.info("do not find the catalog");
            return false;
        }

        Catalog catalog = catalogOptional.get();
        return isNotEmpty(catalog.getSceneList());
    }

    /**
     * 过滤出菜的场景和推荐菜的场景都开启的情况
     *
     * @param finalItem
     * @param itemListInDb
     * @return
     */
    public List<Item> getItems(Item finalItem, List<Item> itemListInDb) throws Exception {

        List<Item> itemList = new ArrayList<>();
        Scene matchScene = null;
        try {
            matchScene = SceneService.getInstance().findTheMatchScene(finalItem.getShopId());
        } catch (Exception e) {
            logger.info("e", e);
        }
        for (Item itemInDb : itemListInDb) {
            //是推荐菜
            if (getBoolean(itemInDb.getSuggestion())) {
                List<PriceConfig> priceConfigList = itemInDb.getPriceConfigList();
                Scene finalMatchScene = matchScene;
                //这个菜当前场景下配置的场景价格
                List<PriceConfig> priceConfigs = priceConfigList.stream().filter(s -> equals(s.getSceneId(), finalMatchScene.getId())).collect(Collectors.toList());
                if (isNotEmpty(priceConfigs)) {
                    PriceConfig priceConfig = priceConfigs.get(0);
                    //推荐菜的场景和菜的场景要同时开启才能显示到b端
                    if (getBoolean(priceConfig.getEnable())) {
                        itemList.add(itemInDb);
                    }
                }
            } else {
                itemList.add(itemInDb);
            }
        }

        return itemList;
    }

    /**
     * 普通菜并且有细节
     *
     * @param item
     * @return
     */
    public static boolean isCommonItemHasDetail(Item item) {
        logger.info("check item {} has detail", item.getId());
        //套餐不满足
        if (BooleanUtils.isTrue(item.getSetMenu())) {
            logger.info("set menu is true");
            return false;
        }

        List<ItemDetail> itemDetailList = item.getItemDetailList();
        //没有细节
        if (CollectionUtils.isEmpty(itemDetailList)) {
            logger.info("item detail list is empty");
            return false;
        }

        //如果细节有，但是只有一行，并且没有名称，也忽略
        if (itemDetailList.size() == 1) {
            ItemDetail itemDetail = itemDetailList.get(0);
            if (StringUtils.isEmpty(itemDetail.getName_zh()) && StringUtils.isEmpty(itemDetail.getName_en())) {
                logger.info("detail name zh and en is empty");
                return false;
            }
        }

        logger.info("yes has item detail");
        return true;
    }


    /**
     * 处理掉菜的场景的shopID跟菜的shopID不一样的菜（以前导入的时候产生的）
     */
    public void dealItemSceneMapping(Item item) throws Exception {

        List<NameAndId> sceneList = item.getSceneList();

        List<NameAndId> filterSceneList = sceneList.stream().filter(s -> {
            Long sceneId = s.getId();
            Scene scene = null;
            try {
                scene = SceneService.getInstance().findScene(sceneId);
            } catch (Exception e) {
                logger.error("e", e);
            }
            return equals(scene.getShopId(), item.getShopId());
        }).collect(Collectors.toList());
        if (isEmpty(filterSceneList)) {
            item.setSuggestion(false);
            CommonService.getInstance().save(item);
        } else {
            item.setSceneList(filterSceneList);
            CommonService.getInstance().save(item);
        }

    }

    /**
     * 同步修改foodpanda的菜名
     *
     * @param itemId
     * @return
     */
    public void sycAllFoodPandaProduct(Long itemId, Long companyId, CompanyMainItem companyMainItem) throws Exception {

        Product product = new Product();
        product.setBelongToItemId(itemId);
        product.setCompanyId(companyId);
        List<Product> productList = CommonService.getInstance().searchAll(product);
        //只要在product里面找到，直接更新
        if (isNotEmpty(productList)) {
            for (Product productInDb : productList) {
                if (isNotEmpty(companyMainItem.getName_zh())) {
                    productInDb.setName_zh(companyMainItem.getName_zh());
                }

                if (isNotEmpty(companyMainItem.getName_en())) {
                    productInDb.setName_en(companyMainItem.getName_en());
                }

                commonService.save(productInDb);
            }

        }

        //不管在product里面有没有找到，如果修改的主菜类型非套餐，都要到熊猫的套餐下面遍历套餐里的菜品
        Product setMenuProduct = new Product();
        setMenuProduct.setCompanyId(companyId);
        setMenuProduct.setSetMenu(true);
        List<Product> setMenuProductList = CommonService.getInstance().searchAll(setMenuProduct);

        for (Product setMenuProductInDb : setMenuProductList) {
            List<Item> itemList = FoodPandaConfigService.getInstance().filterItemInSetMenu(setMenuProductInDb, itemId);

            for (Item item : itemList) {
                if (isNotEmpty(companyMainItem.getName_zh())) {
                    item.setName_zh(companyMainItem.getName_zh());
                }

                if (isNotEmpty(companyMainItem.getName_en())) {
                    item.setName_en(companyMainItem.getName_en());
                }
            }

            commonService.save(setMenuProductInDb);
        }


    }

    /**
     * 删除foodpanda里面的菜和套餐
     *
     * @param itemId
     * @throws Exception
     */
    public void deleteFoodPandaRelateSetMenuItem(Long itemId) throws Exception {
        Item item = findItem(itemId);
        Product productIn = new Product();
        productIn.setEntity(true);
        productIn.setShopId(item.getShopId());
        //找到分店下所有foodPanda菜
        List<Product> productList = commonService.searchAll(productIn);
        List<Product> products = productList.stream().filter(s -> equals(s.getBelongToItemId(), itemId)).collect(Collectors.toList());
        //如果是有值，不管是菜还是套餐直接删
        for (Product product : getList(products)) {
            if (equals(item.getId(),product.getBelongToItemId())) {
                commonService.delete(product);
            }
        }
        //删除套餐里面的菜
        deleteSetMenuItem(itemId, productList);

    }

    /**
     * 删除套餐里面的菜
     *
     * @param itemId
     * @param productList
     * @throws Exception
     */
    private void deleteSetMenuItem(Long itemId, List<Product> productList) throws Exception {
        for (Product product : productList) {
            //找到包含这个菜的的套餐
            boolean containTheItem = productSetMenuItemContainTheItem(product, itemId);
            //没有包含该菜品
            if (!containTheItem) {
                continue;
            }
            //删除套餐里面的菜
            removeTheItemFromSetMenu(product, itemId);
            //重新处理下套餐里面的数据的值
            productDealSetMenuItem(product);
            //删除SetMenuItem里面空itemList
            filterFoodPandaNullItemList(product);
            commonService.save(product);
        }
    }

    /**
     * 如果foodPanda套餐某一项没有菜就过滤掉这一项
     * @param product
     */
    private void filterFoodPandaNullItemList(Product product) {
        List<SetMenuOneItem> setMenuOneItems = getList(product.getSetMenuOneItemList()).stream().filter(s -> isNotEmpty(s.getItemList())).collect(Collectors.toList());
        product.setSetMenuOneItemList(setMenuOneItems);
    }

    /**
     * 如果套餐某一项没有菜就过滤掉这一项
     * @param item
     */
    private void filterNullItemList(Item item) {
        List<SetMenuOneItem> setMenuOneItems = getList(item.getSetMenuOneItemList()).stream().filter(s -> isNotEmpty(s.getItemList())).collect(Collectors.toList());
        item.setSetMenuOneItemList(setMenuOneItems);
    }

    /**
     * 处理套餐里面的每一项菜品
     *
     * @param wholeItem
     */
    public void productDealSetMenuItem(Product wholeItem) throws Exception {
        if (!getBoolean(wholeItem.getSetMenu())) {
            logger.info("not the set menu item");
            return;
        }

        List<SetMenuOneItem> setMenuOneItemList = wholeItem.getSetMenuOneItemList();
        if (isEmpty(setMenuOneItemList)) {
            logger.info("set menu item list is empty");
            return;
        }

        //套餐里面的每一项
        for (SetMenuOneItem setMenuOneItem : wholeItem.getSetMenuOneItemList()) {
            List<Item> itemList = setMenuOneItem.getItemList();
            //套餐里面的每一项
            for (Item item : itemList) {
                ItemService itemService = ItemService.getInstance();
                Item itemInDb = itemService.findItem(item.getId());
                //将数据库里面的数据写到请求里面来
                BeanUtils.copyProperties(itemInDb, item, "setMenuAddPrice");
            }

            if (setMenuOneItem.getId() == null) {
                logger.info("will create item catalog id");
                //如果是套餐，套餐里面的标签ID唯一生成
                Long itemCatalogId = OrderService.getInstance().generateOrderItemId(wholeItem.getShopId());
                setMenuOneItem.setId(itemCatalogId);
            }
        }
    }


    /**
     * 将菜品从套餐里面移除
     *
     * @param item
     */
    public void removeTheItemFromSetMenu(Product item, Long itemId) {
        List<SetMenuOneItem> setMenuOneItemList = getList(item.getSetMenuOneItemList());
        for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
            List<Item> itemList = getList(setMenuOneItem.getItemList());
            setMenuOneItem.setItemList(itemList.stream().filter(i -> !equals(i.getId(), itemId)).collect(Collectors.toList()));
        }
    }

    /**
     * 套餐是否已经包含了这个菜品
     *
     * @param item
     * @param itemId
     */
    public boolean productSetMenuItemContainTheItem(Product item, Long itemId) {
        if (!getBoolean(item.getSetMenu())) {
            logger.info("not the set menu item");
            return false;
        }

        List<SetMenuOneItem> setMenuOneItemList = getList(item.getSetMenuOneItemList());
        if (isEmpty(setMenuOneItemList)) {
            logger.info("set menu one item list is empty");
            return false;
        }

        for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
            List<Item> itemList = getList(setMenuOneItem.getItemList());
            //没有任何菜，判断下一个菜
            if (isEmpty(itemList)) {
                continue;
            }

            Optional<Item> optionalItem = itemList.stream().filter(i -> equals(i.getId(), itemId)).findAny();
            if (optionalItem.isPresent()) {
                logger.info("find the item {} in set menu item {}", itemId, item.getId());
                return true;
            }

            continue;
        }

        //最后都没有找到
        return false;
    }

}
